#ifdef WIN32
#include <Windows.h>
#endif

#include "camera.h"
#include <GL/glew.h>
#include <math.h>

static const float PI = 3.1415926f ;

Camera::Camera():
m_dest(Vec3(0.0,0.0,0.0)),
m_zpy(Vec3(4.0,0.0,0.0)),
m_up(Vec3(0.0,1.0,0.0)),
m_fov(60.0),
m_perspective(true),
navMode(ORBIT)
{
	evalCampos();
}

Camera::Camera(Vec3 zpy, Vec3 dest, Vec3 up,float fov):
m_dest(dest),
m_zpy(zpy),
m_up(up),
m_fov(fov),
m_perspective(true),
navMode(ORBIT)
{
	evalCampos();
	m_pos_init = m_campos;
	m_dest_init = dest;
}

Camera::~Camera()
{

}

void Camera::MVTransform()
{
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
	gluLookAt( m_campos.x, m_campos.y, m_campos.z, m_dest.x, m_dest.y, m_dest.z, m_up.x, m_up.y, m_up.z );
}

void Camera::toggleProjectionMode()
{
	m_perspective = !m_perspective;
}

void Camera::PTransform(float ratio)
{
	if(m_perspective)
	{
		glMatrixMode( GL_PROJECTION );
		glLoadIdentity();
		gluPerspective( m_fov, ratio, 0.1, 100.0 );
	}
	else
	{
		glMatrixMode( GL_PROJECTION );
		glLoadIdentity();
		glOrtho( -0.5*m_zpy.x, 0.5*m_zpy.x, -0.5*m_zpy.x,0.5*m_zpy.x,0.1, 100.0 );
	}

}

void Camera::fov(float decal)
{
	m_fov+= decal;
}

void Camera::pan(float x, float y)
{
	Vec3 camdirection = m_dest - m_campos ;

	Vec3 up;
	up.x =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * sin( m_zpy.z );
	up.y =  m_zpy.x * sin( 0.5f*PI + m_zpy.y );
	up.z =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * cos( m_zpy.z );
	up.Normalize();
	Vec3 right = up ^ camdirection ;
	right.Normalize();

	Vec3 decal = m_zpy.x*0.0027f*x*right + m_zpy.x*0.0027f*y*up ;
	m_dest += decal;

	evalCampos();
}

void Camera::decal(Vec3 decal)
{
	m_dest = m_dest_init+decal;
	m_campos = m_pos_init+decal;
	evalCampos();
}

void Camera::zoom(float factor)
{
	if (m_zpy.x*(1.0+factor*0.01)>0.0)
	{
		m_zpy.x *= 1.0f+factor*0.01f ;
		evalCampos();
	}
	if(!m_perspective)
	{
		glMatrixMode( GL_PROJECTION );
		glLoadIdentity();
		glOrtho( -1.0*m_zpy.x, 1.0*m_zpy.x, -1.0*m_zpy.x,1.0*m_zpy.x,0.1, 100.0 );
	}

}

void Camera::rotate(float pitch, float yaw)
{
	m_zpy.y += pitch ;
	if (m_zpy.y > 0.499f*PI) m_zpy.y = 0.499f*PI ;
	if (m_zpy.y < -0.499f*PI ) m_zpy.y = -0.499f*PI ;
	m_zpy.z += yaw ;

	evalCampos();
}

void Camera::forward(float decal)
{
	Vec3 dir = m_dest - m_campos;
	dir.Normalize();
	m_campos += decal*dir;
	m_dest += decal*dir;
}

void Camera::up(float angle)
{
	Vec3 dir = m_dest - m_campos ;

	Vec3 up;
	up.x =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * sin( m_zpy.z );
	up.y =  m_zpy.x * sin( 0.5f*PI + m_zpy.y );
	up.z =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * cos( m_zpy.z );
	up.Normalize();

	Vec3 ray = (m_dest + angle*up) - m_campos;
	ray.Normalize();

	m_zpy.y -= atan(angle/dir.Norm());
	m_dest = m_campos + m_zpy.x*ray;
}

void Camera::twist(float angle)
{
	Vec3 up;
	Vec3 dir = m_dest - m_campos ;
	up.x =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * sin( m_zpy.z );
	up.y =  m_zpy.x * sin( 0.5f*PI + m_zpy.y );
	up.z =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * cos( m_zpy.z );
	up.Normalize();
	Vec3 right = up ^ dir ;
	right.Normalize();

	m_up = cos(angle)*up + sin(angle)*right ;
}

void Camera::right(float angle)
{
	Vec3 dir = m_dest - m_campos ;

	Vec3 up;
	up.x =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * sin( m_zpy.z );
	up.y =  m_zpy.x * sin( 0.5f*PI + m_zpy.y );
	up.z =  m_zpy.x * cos( 0.5f*PI + m_zpy.y ) * cos( m_zpy.z );
//	 Vec3 up = Vec3(0.0,1.0,0.0);
	Vec3 right = up ^ dir ;
	right.Normalize();

	Vec3 ray = (m_dest + angle*right) - m_campos;
	ray.Normalize();

	m_zpy.z += atan(angle/dir.Norm());
	m_dest = m_campos + m_zpy.x*ray;
}

void Camera::reset()
{
	m_dest = Vec3(0.0,0.0,0.0) ;
	m_zpy = Vec3(4.0,0.0,0.0) ;
	m_up = Vec3(0.0,1.0,0.0) ;
	evalCampos();
}


void Camera::evalCampos()
{
	m_campos.x = m_dest.x + m_zpy.x * cos( m_zpy.y ) * sin( m_zpy.z );
	m_campos.y = m_dest.y + m_zpy.x * sin( m_zpy.y );
	m_campos.z = m_dest.z + m_zpy.x * cos( m_zpy.y ) * cos( m_zpy.z );
}





